#!/usr/bin/python3
# -*- coding:utf-8 -*-
import os
import re
import shutil
import signal
import subprocess
import csv
import yaml
import time
import datetime
import base64
from subprocess import check_output
from BladeFerm.Lib.Common import logger


def is_chinese(string):
    """
    检查整个字符串是否包含中文
    :param string: 需要检查的字符串
    :return: bool
    """
    for ch in string:
        if u'\u4e00' <= ch <= u'\u9fff':
            return True
    return False


def shut_process(lst_port):
    '''
    根据应用程序对应的端口号杀掉对应的进程
    :param lst_port: 转化成list，含要杀掉的端口号
    :return:
    '''

    # 查找进程id
    def foud_pid(port):
        new_pid_lst = []
        cmd1 = "netstat -ano | findstr %s" % str(port)
        res1 = run_command(cmd1)
        logger.info(f'Cmd: {cmd1}')
        if len(res1) > 0:
            pid_lst = []
            for line in res1:
                line_info = line.decode()
                pid = line_info.split(' ')[-1]
                pid_lst.append(pid)
            new_pid_lst = list(set(pid_lst))
        else:
            logger.info(f'Query none.')
        return new_pid_lst

    #  杀进程
    def shutdown(new_pid_lst):
        if len(new_pid_lst) > 0:
            for pid2 in new_pid_lst:
                cmd2 = 'taskkill /f /pid %4s' % str(pid2)
                res2 = run_command(cmd2)
        return True
    # 主
    def main_shut(port_lst):
        if len(port_lst) > 0:
            pid_1 = foud_pid(port_lst[0])
            if len(port_lst) == 2:
                pid_2 = foud_pid(port_lst[1])
                pid_set = set(pid_1) & set(pid_2)
                pid_list = list(pid_set)
            else:
                pid_list = pid_1.copy()
        else:
            pid_list = []
        shutdown(pid_list)
        query_res = foud_pid(port_lst[-1])
        if len(query_res) == 0:
            return True
        else:
            return False

    # 主逻辑
    if not isinstance(lst_port, list):
        lst_port = [lst_port]
    # 增加重试机制
    res = False
    for i in range(3):
        logger.info(f'Shutdow process no.{i} ')
        res = main_shut(lst_port)
        if res:
            break
        else:
            i += 1
    return res


def read_file(filepath):
    with open(filepath, 'r', encoding='utf-8') as f:
        content = f.read()
    return content


def write_file(filepath, content):
    with open(filepath, 'w', encoding='utf-8', newline='') as f:
        f.write(content)
    return True


def is_dir_exist(path):
    try:
        ext = os.path.exists(path)
        if not ext:
            os.mkdir(path)
            logger.info(f"新建目录: {path}")
        return True
    except Exception as e:
        logger.error(f"error: {e}")
        return False


def str_decode(str):
    # 解码：base64编码 -> 二进制 -> 字符串
    raw_str = base64.b64decode(str.encode()).decode()
    return raw_str


def get_curtime(format_str = "%Y-%m-%d %H:%M:%S"):
    ct = time.strftime(format_str, time.localtime())
    return ct


def get_TargetTime(otherDay=1, format='%Y-%m-%d'):
    today = datetime.date.today()
    tomorrow = today + datetime.timedelta(days=otherDay)
    return tomorrow.strftime(format)


def delete_dir(path):
    result = False
    try:
        shutil.rmtree(path)
        index = 0
        while index < 10:
            time.sleep(1)
            index += 1
            if not os.path.exists(path):
                result = True
                break
    except Exception as e:
        logger.error(f'删除目录 {path} 出现异常： {e}')
        result = False
    return result


def clear_dir(path):
    '''
    清空目录
    :param path:
    :return:
    '''
    flag = delete_dir(path)
    if flag:
        result = is_dir_exist(path)
        logger.info(f'清空目录： {path}')
    else:
        result = False
    return result


def delete_dir_files(filepath):
    files = os.listdir(filepath)
    os.system(f"attrib -r {filepath}")
    for file in files:
        filename = os.path.join(filepath, file)
        try:
            if os.path.exists(filename):
                os.remove(filepath)
                logger.info(f'删除文件 {filename} ')
        except Exception as e:
            logger.error(f'删除文件 {filename} 发送异常：{e}')
    else:
        return True


def delete_file(filepath):
    try:
        if os.path.exists(filepath):
            os.remove(filepath)
        return True
    except Exception:
        return False


def delete_dir_file(filename, base_dir):
    files = os.listdir(base_dir)
    count = 0
    for file in files:
        if re.search(filename, file):
            os.remove(os.path.join(base_dir, file))
            logger.info(f'删除文件：{file}')
            count += 1
    return count

def read_csv(filename):
    res_con = []
    with open(filename, 'r') as f:
        content = csv.reader(f)
        headline = next(content)
        hl = ','.join(headline)
        res_con.append(hl)
        for line in content:
            print('1', len(line))
            print(line)
            sl = ''
            for unit in line:
                if unit == '':
                    sl += "'',"
                elif unit == ' ':
                    sl += "' ',"
                else:
                    sl += unit+','
            print(sl)
            print('2', len(sl.split(',')))
            res_con.append(sl)
    return res_con


def write_csv(file_name, rows, headers=None):
    '''
    写csv操作
    :param file_name: 文件名
    :param rows: [{k:v, k1:v1}{k:v}]
    :param headers: [k, k1]
    :return:
    '''
    with open(file_name, 'a')as f:
        f_csv = csv.DictWriter(f, headers)
        if headers is not None:
            f_csv.writeheader()         # 如果需要写入标题就可以
        f_csv.writerows(rows)
        f.close()


def rename_file(srcFile, new_name):
    path, filename = os.path.split(srcFile)
    dstFile = os.path.join(path, new_name)
    try:
        os.rename(srcFile, dstFile)
    except Exception as e:
        print(e)
        print('rename file fail\r\n')
    else:
        print('rename file success\r\n')


def query_dirs(tar_path):
    dir_list = []
    if os.path.exists(tar_path):
        res_lst = os.listdir(tar_path)
        for path in res_lst:
            if os.path.isdir(path):
                path2 = os.path.join(tar_path, path)
                dir_list.append(path2)
    return dir_list


def run_command(cmd):
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    return p.stdout.readlines()


def run_bat_script(file_path):
    logger.info(f'Run bat file: {file_path}')
    fp, fn = os.path.split(file_path)
    cur_path = os.getcwd()
    os.chdir(fp)
    os.startfile(fn)
    logger.info(f'{file_path} runs successfully!')
    os.chdir(cur_path)
    return os.getcwd()


def run_bat(bat_name):
    fpath, fname = os.path.split(bat_name)
    b_name, a_ex = os.path.splitext(fname)
    log_name = '%s_result.txt' % b_name
    run_log_path = os.path.join(fpath, log_name)
    cur_dir = os.getcwd()
    os.chdir(fpath)
    bat_cmd = fname + ' >' + log_name
    p = subprocess.Popen(bat_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    p.communicate(timeout=1200)
    statu = p.returncode
    os.chdir(cur_dir)
    logger.info('log route:%s' % run_log_path)
    if statu == 0:
        logger.info('%s update sucsess!' % fpath)
    else:
        logger.info('%s update fail!' % fpath)
    return run_log_path


def run_bat2(bat_name):
    cur_time = get_curtime('%Y%m%d%H%M%S')
    fpath, fname = os.path.split(bat_name)
    b_name, a_ex = os.path.splitext(fname)
    log_name2 = '%s_result_%s.txt' % (b_name, cur_time)
    run_log_path = os.path.join('./logs', log_name2)
    fh = open(run_log_path, 'w', encoding='utf-8')
    cur_dir = os.getcwd()
    os.chdir(fpath)
    log_name = '%s_result.txt' % b_name
    bat_cmd = fname # + ' >' + log_name
    # try:
    p = subprocess.Popen(bat_cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    print(p.stdout.readlines())
    for line in p.stdout.readlines():
        print(line.decode())
    os.chdir(cur_dir)


def rewrite_bat(filepath, tar_dict):
    path, name  = os.path.split(filepath)
    filename = 'install_%s.bat' % tar_dict['tnsname']
    new_path = os.path.join(path, filename)
    with open(filepath, 'r', encoding='gbk') as fn:
        lines = fn.readlines()
    newlines = []
    for line in lines:
        res = re.match('set /p (.*)=', line)
        res2 = re.match('pause ', line)
        if res is not None and res2 is None:
            new_str = 'set %s=%s\n' % (res[1], tar_dict[res[1]])
            newlines.append(new_str)
        elif res2 is not None and res is None:
            new_str2 = 'echo contine \n'
            newlines.append(new_str2)
        else:
            newlines.append(line)
    with open(new_path, 'w', encoding='gbk') as fn2:
        fn2.writelines(newlines)
    return new_path


def judge_type(filepath):
    if re.search('FERM20-平台基础升级包', filepath) is not None:
        f_type = 'bat_frem'
        return f_type
    if re.search('FSK-NC-数据库升级包', filepath) is not None:
        f_type = 'bat_nc'
        return f_type
    if re.search('FSK-数据库升级包', filepath) is not None:
        f_type = 'bat_fsk'
        return f_type


def sort_db_lst(file_lst):
    new_file_lst = []
    if len(file_lst) > 0:
        for filepath in file_lst:
            if re.search('FERM20-平台基础升级包', filepath) is not None:
                new_file_lst.append(filepath)
        for filepath in file_lst:
            if re.search('FSK-数据库升级包', filepath) is not None:
                new_file_lst.append(filepath)
        for filepath in file_lst:
            if re.search('FSK-NC-数据库升级包', filepath) is not None:
                new_file_lst.append(filepath)
    return new_file_lst


def select_db(db_list, num=1):
    '''
    从列表中筛选出fsk，nc，flow等3中数据包
    :param db_list: 原始列表
    :param num: 根据num参数取最新的n个，当num大于分类后包的数量，展示所有
    :return:
    '''
    af_num = -num
    fnc = []
    fsk = []
    flow = []
    logger.info('远程获取的FSK,FSK-NC,工作流如下：')
    for file in db_list:
        logger.info(str(file))
        # path, name = os.path.split(file)
        r1 = re.search('FSK-数据库升级包', file)
        r2 = re.search('FSK-NC-数据库升级包', file)
        if r1 is not None and r2 is None:
            fsk.append(file)
        elif r1 is None and r2 is not None:
            fnc.append(file)
        else:
            flow.append(file)
    if len(fsk) >= num:
        fsk2 = []
        for unit in fsk[af_num:]:
            fsk2.append(unit)
    else:
        fsk2 = fsk
    if len(fnc) >= num:
        fnc2 = []
        for unit in fnc[af_num:]:
            fnc2.append(unit)
    else:
        fnc2 = fnc
    if len(flow) >= num:
        flow2 = []
        for unit in flow[af_num:]:
            flow2.append(unit)
    else:
        flow2 = flow
    new_list = fsk2 + fnc2 + flow2
    return fnc, fsk, flow, new_list


def read_yaml(yaml_path):
    with open(yaml_path, 'r', encoding='utf-8') as f:
        cons = yaml.safe_load(f.read())
    return cons


def write_yaml(yaml_path, contents):
    with open(yaml_path, "w", encoding="UTF-8") as f:
        yaml.dump(contents, f)
    return True


def read_log():
    log_path3 = 'logs/RunInfo_%s.log' % time.strftime("%Y%m%d", time.localtime())
    with open(log_path3, 'r', encoding='gbk') as fn:
        lines = fn.readlines()
    length = len(lines)
    return lines, length


def show_logs():
    lines, length = read_log()
    for line in lines:
        if re.search(' INFO] ', line):
            print(line)


def judge_file_newest(filename):
    logger.info(f'Judge filename {filename}')
    time_str = get_curtime('%Y%m%d')
    result = re.search(time_str, filename)
    if result is None:
        return False
    else:
        return True


def check_fail_info(fileanme, fail_flags=None, encode='utf-8'):
    '''
    运行日志分析，查找错误信息
    :param fileanme: 运行日志文件名称
    :param fail_flags: 失败信息标准
    :return:
    '''
    fail_lines = []
    with open(fileanme, 'r', encoding=encode) as f:
        cons = f.readlines()
    logger.info(f'以下是脚本运行失败的信息：')
    runlog = cons.copy()
    i = 0
    while i < len(cons):
        if cons[i] != '' and fail_flags is not None:
            for flag in fail_flags:
                res = re.search(flag, cons[i])
                if res is not None:
                    logger.error('************************失败信息如下************************')
                    fail_lines += runlog[i-5: i+1]
                    fail_info = '\n'.join(fail_lines)
                    logger.info(f'{fail_info}')
        i += 1
    return fail_lines


def parse_log(fileanme, success_flag='升级成功', fail_flags=None):
    fp, fn = os.path.split(fileanme)
    name, ext = os.path.splitext(fn)
    new_name = name + "_%s" % get_curtime("%Y%m%d%H%M%S") + ext
    with open(fileanme, 'r', encoding='gbk') as f:
        con = f.read()
    bak_name = os.path.join('./logs', new_name)
    with open(bak_name, 'w', encoding='utf-8') as f2:
        f2.write(con)
    if re.search(success_flag, con) is not None:
        logger.info(f'{fp} 升级成功！')
        logger.info(f'脚本运行日志：{bak_name}。')
        return True
    else:
        logger.warning(f'{fp} 升级失败！')
        logger.info(f'详细失败信息请查看脚本运行日志：{bak_name}。')
        logger.info('若是因为编译原因，请人工到数据库进行无效编译。其他问题可先解决再重新升级！')
        check_fail_info(bak_name, fail_flags)
        return False


def get_dir_file(path, index=-1):
    files = os.listdir(path)
    return files[index] if files else None


# linux 系统试用
def get_pid(name):
    return map(int, check_output(["pidof", name]).split())


def get_process_id(name):
    child = subprocess.Popen(['pgrep', '-f', name],stdout=subprocess.PIPE, shell=False)
    response = child.communicate()[0]
    return [int(pid) for pid in response.split()]


def kill(pid_lst):
    if not isinstance(pid_lst, list):
        pid_lst = [pid_lst]
    try:
        for pid in pid_lst:
            a = os.kill(pid, signal.SIGKILL)
            # a = os.kill(pid, signal.9) #　与上等效
            logger.info('已杀死pid为%s的进程,　返回值是:%s' % (pid, a))
    except OSError as e:
        logger.warning('没有如此进程!!!')
    return True


def shutdowndown(cmd):
    """
    执行打包操作
    Returns:

    """
    logger.info(f'执行的命令：{cmd}')
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    p.communicate(timeout=1200)
    status = p.returncode
    logger.info(f'status: {status}')


if __name__ == '__main__':
    bat_name = 'D:\FREM_ZIP\\20210304\FSK-NC-数据库升级包(基于V202004-0-0)_V202101-1-0.202103040647\install_36_97.bat'
    palt_name = '/PLAT/script/FERM20-平台基础升级包(基于V202101-0-0)_V202101-1-0V202103100321.zip'
    # res = judge_file_newest(palt_name)
    # print(res)
    res = get_process_id('my_job')
    print('res', res)